﻿using System;
using System.Text;
using System.Text.RegularExpressions;
using System.Collections.Generic;

namespace SolutionGeneratorHelper
{
    internal static class SolutionConfigType
    {
        internal const string SolutionPlatforms = "SolutionConfigurationPlatforms";
        internal const string ProjectPlatforms = "ProjectConfigurationPlatforms";
    }

    internal class SolutionConfig : CommonNode
    {
        private static readonly Regex SectionConfigDeclaration = new Regex("(?<name>[^\f\n\r\t\v]+) = (?<value>[^\f\n\r\t\v]+)");

        private Field m_label;
        internal Field Label { get => m_label; set => SetField(ref m_label, value); }

        private Field m_sectionType;
        internal Field SectionType { get => m_sectionType; set => SetField(ref m_sectionType, value); }


        internal SolutionConfig(Field _label, Field _sectionType)
        {
            Label = _label;
            SectionType = _sectionType;
        }

        internal virtual void ParseSolutionConfig(string _content)
        {
            MatchCollection mc = SectionConfigDeclaration.Matches(_content);
            foreach (Match item in mc)
            {
                // Console.WriteLine("name->{0}", item.Groups["name"].ToString());
                // Console.WriteLine("value->{0}", item.Groups["value"].ToString());
                Node n = new SolutionConfigItem();
                n.Content = new Field(item.Groups["name"].ToString(), item.Groups["value"].ToString());
                InsertChild(n);
            }
            Console.WriteLine("SolutionConfig ParseSolutionConfig");
        }

        internal static SolutionConfig GetSolutionConfigType(Field _label, Field _sectionType)
        {
            if (SolutionConfigType.ProjectPlatforms == _label.Value)
                return new ProjectPlatformsConfig(_label, _sectionType);
            if (SolutionConfigType.SolutionPlatforms == _label.Value)
                return new SolutionPlatformsConfig(_label, _sectionType);
            return new SolutionConfig(_label, _sectionType);
        }

        public override void Serialize(StringBuilder _sb)
        {
            _sb.AppendFormat("\r\n\tGlobalSection({0}) = {1}", Label.Value, SectionType.Value);
            base.Serialize(_sb);
            _sb.Append("\r\n\tEndGlobalSection");
        }
    }

    internal class SolutionConfigItem : CommonNode
    {
        public override void Serialize(StringBuilder _sb)
        {
            _sb.AppendFormat("\r\n\t\t{0} = {1}", Content.Attr, Content.Value);
        }
    }

    internal class SolutionPlatformsConfigMode : SolutionConfigItem
    {
        public override void Serialize(StringBuilder _sb)
        {
            _sb.AppendFormat("\r\n\t\t{0}|{1} = {0}|{1}", Content.Attr, Content.Value);
        }
    }

    internal class SolutionPlatformsConfig : SolutionConfig
    {
        private static readonly Regex SolutionPlatformsDeclaration = new Regex("(?<name>[^\f\n\r\t\v]+)\\|(?<value>[^\f\n\r\t\v]+) = [^\f\n\r\t\v]+");

        internal SolutionPlatformsConfig(Field _label, Field _sectionType) : base(_label, _sectionType) { }

        internal override void ParseSolutionConfig(string _content)
        {
            MatchCollection mc = SolutionPlatformsDeclaration.Matches(_content);
            foreach (Match item in mc)
            {
                // Console.WriteLine("name->{0}", item.Groups["name"].ToString());
                // Console.WriteLine("value->{0}", item.Groups["value"].ToString());
                Node n = new SolutionPlatformsConfigMode();
                n.Content = new Field(item.Groups["name"].ToString(), item.Groups["value"].ToString());
                InsertChild(n);
                ((Solution)Parent).SolutionPlatforms = this;
            }
            Console.WriteLine("SolutionPlatformsConfig ParseSolutionConfig");
        }

        public override void Serialize(StringBuilder _sb)
        {
            base.Serialize(_sb);
        }
    }


    internal class ProjectPlatformsConfigMode : SolutionConfigItem
    {
        private string m_mode;
        internal string Mode { get => m_mode; set => m_mode = value; }

        private ProjectRef m_projRef;
        internal ProjectRef ProjRef { get => m_projRef; set => m_projRef = value; }

        private Dictionary<string, string> m_option;
        internal Dictionary<string, string> Option { get => m_option; set => m_option = value; }


        protected override void Init()
        {
            base.Init();
            m_option = new Dictionary<string, string>();
        }

        public override void Serialize(StringBuilder _sb)
        {
            foreach (var item in Option)
            {
                _sb.AppendFormat("\r\n\t\t{{{0}}}.{1}|{3}.{2} = {1}|{3}", ProjRef.ProjectGuid.Value, Mode, item.Key, item.Value);
            }
        }
    }


    internal class ProjectPlatformsConfig : SolutionConfig
    {
        private const string strSectionItemDeclarationBegin = "\\{";
        private const string strSectionItemDeclarationEnd = "\\}\\.(?<mode>[\\w]+)\\|(?<value>[A-z a-z]+)\\.(?<option>.*)\\s=\\s(\\w)+\\|[A-z a-z]+";

        private Dictionary<string, List<ProjectPlatformsConfigMode>> m_modes;
        public Dictionary<string, List<ProjectPlatformsConfigMode>> Modes { get => m_modes; set => m_modes = value; }


        internal ProjectPlatformsConfig(Field _label, Field _sectionType) : base(_label, _sectionType) { }

        protected override void Init()
        {
            base.Init();
            m_modes = new Dictionary<string, List<ProjectPlatformsConfigMode>>();
        }

        internal override void ParseSolutionConfig(string _content)
        {
            Solution parent = (Solution)Parent;
            foreach (ProjectRef projRef in parent.ProjectRefs)
            {
                ParseConfig(projRef, _content);
            }
            Console.WriteLine("ProjectPlatformsConfig ParseSolutionConfig");
        }

        private void ParseConfig(ProjectRef _projRef, string _content)
        {
            string strReg = strSectionItemDeclarationBegin + _projRef.ProjectGuid.Value + strSectionItemDeclarationEnd;
            Regex projectPlatformsDeclaration = new Regex(strReg);
            MatchCollection mc = projectPlatformsDeclaration.Matches(_content);
            foreach (Match item in mc)
            {
                // Console.WriteLine("mode->{0}", item.Groups["mode"].ToString());
                // Console.WriteLine("option->{0}", item.Groups["option"].ToString());
                // Console.WriteLine("value->{0}", item.Groups["value"].ToString());
                UpdateConfig(
                    _projRef,
                    item.Groups["mode"].ToString(),
                    item.Groups["option"].ToString(),
                    item.Groups["value"].ToString()
                );
            }
        }

        internal void UpdateConfig(ProjectRef _projRef, string _mode, string _option, string _value)
        {
            List<ProjectPlatformsConfigMode> ppcms = null;
            Modes.TryGetValue(_projRef.ProjectGuid.Value, out ppcms);
            if (null == ppcms)
            {
                ppcms = new List<ProjectPlatformsConfigMode>();
                Modes.Add(_projRef.ProjectGuid.Value, ppcms);
            }

            ProjectPlatformsConfigMode ppcm = null;
            foreach (ProjectPlatformsConfigMode item in ppcms)
            {
                if (_mode == item.Mode)
                {
                    ppcm = item;
                    break;
                }
            }

            if (null == ppcm)
            {
                ppcm = new ProjectPlatformsConfigMode();
                ppcm.Mode = _mode;
                ppcm.ProjRef = _projRef;
                ppcms.Add(ppcm);
                InsertChild(ppcm);
                ((Solution)Parent).ProjectPlatforms = this;
            }

            ppcm.Option.TryGetValue(_option, out string value);
            if (null == value)
                ppcm.Option.Add(_option, _value);
            else
                ppcm.Option[_option] = _value;
        }

        public override void Serialize(StringBuilder _sb)
        {
            base.Serialize(_sb);
        }
    }
}
